package scales.xml.serializers
import scales.xml.impl.NamespaceDefaults
import scales.xml.{EmptyDoc, XmlItem, DocLike,
Misc, XmlVersion, Declaration,
XmlPull, ScalesXml, Elem}
import scales.utils._
import scala.collection.immutable.{ Stack, Map }
import resources._
import java.io.Writer
import java.nio.charset.Charset
trait XmlPrinterImplicits {
implicit def fromSerializeableToWriteTo[T : SerializeableXml]( it : T ) =
new WriteTo[T](it)
implicit val defaultSerializerFactory : SerializerFactory = LSSerializerFactory
case class DeclarationConverter(decl: Declaration) {
def withWriter(out: Writer): SerializerData = scales.xml.withWriter(decl, out)
}
implicit def toWithWriter(decl: Declaration) = DeclarationConverter(decl)
}
trait XmlPrinter {
def laddNS(entry: (String, String), mappings: Map[String, String], declMap: Map[String, String]) = {
val mapping = mappings.get(entry._1)
if (mapping.isDefined) {
if (mapping.get == entry._2) {
(mappings, declMap)
} else {
(mappings.updated(entry._1, entry._2),
declMap + entry)
}
} else {
(mappings + (entry._1 -> entry._2),
declMap + entry)
}
}
def doElement(x: Elem, currentMappings : Map[String, String]) = {
import ScalesXml._
var (mappings, declMap) = x.namespaces.foldLeft(
(currentMappings, Map[String, String]()))((p, a) => laddNS(a, p._1, p._2))
val t = x.attributes.foldLeft((mappings, declMap)) { (p, a) =>
val e = a
if (e.prefix.isDefined)
laddNS((e.prefix.get, e.namespace.uri), p._1, p._2)
else p
}
mappings = t._1
declMap = t._2
val addedDefaultNS = {
val currentDefault = mappings(NamespaceDefaults.namespace.uri)
if (x.name.namespace != NamespaceDefaults.noNamespace) {
if (x.name.prefix.isDefined) {
val (imappings, ideclMap) = laddNS((x.name.prefix.get, x.name.namespace.uri), mappings, declMap)
mappings = imappings
declMap = ideclMap
false
} else {
if (currentDefault == x.name.namespace.uri) {
false
} else {
mappings = mappings.updated(NamespaceDefaults.namespace.uri, x.name.namespace.uri)
true
}
}
} else {
if (currentDefault == NamespaceDefaults.noNamespace.uri) {
false
} else {
mappings = mappings.updated(NamespaceDefaults.namespace.uri, NamespaceDefaults.noNamespace.uri)
true
}
}
}
declMap = declMap - NamespaceDefaults.namespace.uri
val default = x.namespaces.get(NamespaceDefaults.namespace.uri)
val addDef =
if (addedDefaultNS || default.isDefined) {
Some(mappings(NamespaceDefaults.namespace.uri))
} else
None
NamespaceContext(mappings, declMap, addDef)
}
def withWriter(decl: Declaration, out: Writer): SerializerData = SerializerData(out, decl.version, decl.encoding)
def serializeMisc(pout: XmlOutput, misc: Iterable[Misc], serializer: Serializer) = {
val opt = misc.foldLeft(None: Option[Throwable]) { (x, m) =>
x.orElse {
serializer.item(m.fold[XmlItem](z => z, y => y), List())
}
}
(pout, opt)
}
def headerAndFooter(pout: XmlOutput, doc: DocLike)(serializerf: (XmlOutput, Serializer) => (XmlOutput, Option[Throwable])): Serializer => Option[Throwable] = { serializer =>
var out = pout
serializer.xmlDeclaration(pout.data.encoding, pout.data.version).orElse {
None
}.orElse {
val (pout, opt) = serializeMisc(out, doc.prolog.misc, serializer)
out = pout
opt
}.orElse {
val (pout, opt) = serializerf(out, serializer)
out = pout
opt
}.orElse {
val (pout, opt) = serializeMisc(out, doc.end.misc, serializer)
out = pout
opt
}
}
type CloseablePull = XmlPull with java.io.Closeable with IsClosed
def foldPrint[T: SerializeableXml](pout: XmlOutput)(it: T) =
serialize(pout)(it)
def serialize[T: SerializeableXml](pout: XmlOutput)(it: T) =
pout.serializerF {
val sxml = implicitly[SerializeableXml[T]]
headerAndFooter(pout, sxml.doc(it))(
sxml(it))
}(pout.data)
def writeTo[T](it: T, output : Writer, version: Option[XmlVersion] = None, encoding: Option[Charset] = None)(implicit serializerFI: SerializerFactory, sxml: SerializeableXml[T]) : Option[Throwable] = {
val decl = sxml.doc(it).prolog.decl
val sd = SerializerData(output,
version.getOrElse(decl.version),
encoding.getOrElse(decl.encoding))
val xo = XmlOutput(sd)
serialize(xo)(it)
}
def printTree[T](xml: T)(implicit serf: SerializerFactory, sxml: SerializeableXml[T]): Unit = {
val out = new java.io.PrintWriter(System.out)
val decl = sxml.doc(xml).prolog.decl
serialize(XmlOutput(SerializerData(out, decl.version, decl.encoding)))(xml) foreach { e =>
out.println("Could not serialize got the following exception " + e.getClass.getName + " - " + e.getMessage)
e.printStackTrace(out)
}
out.flush
println()
}
def asString[T](xml: T)(implicit serf: SerializerFactory, sxml: SerializeableXml[T]): String = {
val builder = new java.io.StringWriter()
val decl = sxml.doc(xml).prolog.decl
foldPrint(XmlOutput(SerializerData(builder, decl.version, decl.encoding)))(xml) foreach {
throw _
}
builder.toString
}
def itemAsString(xmlItem: XmlItem)(implicit serf: SerializerFactory): String = {
implicit val items = new SerializeableXml[XmlItem] {
def doc(it: XmlItem) = EmptyDoc()
def apply(it: XmlItem)(out: XmlOutput, serializer: Serializer): (XmlOutput, Option[Throwable]) = (out, serializer.item(it, out.path))
}
val builder = new java.io.StringWriter()
val o = XmlOutput(SerializerData(builder))
serf{ s =>
s.item(xmlItem, o.path)
}(o.data)
builder.toString
}
}